﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Threading;

using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;

namespace Jack.RedisLib
{
    public interface IRedisClientFactory : IDisposable
    {
        IRedisClient Create(string name);
        Lazy<IRedisClient> LazyCreate(string name);
    }

    public class RedisClientFactory : IRedisClientFactory, IDisposable
    {
        private readonly IOptionsMonitor<RedisOptions> _optionsMonitor;
        private readonly ILogger<RedisClient> _logger;
        private readonly ConcurrentDictionary<string, Lazy<IRedisClient>> _clients;
        private readonly Func<string, Lazy<IRedisClient>> _factory;

        public RedisClientFactory(IOptionsMonitor<RedisOptions> optionsMonitor, ILogger<RedisClient> logger)
        {
            _optionsMonitor = optionsMonitor;
            _logger = logger;
            _clients = new ConcurrentDictionary<string, Lazy<IRedisClient>>(StringComparer.OrdinalIgnoreCase);

            _factory = (name) =>
            {
                RedisOptions redisOptions = _optionsMonitor.Get(name);
                return new Lazy<IRedisClient>(() => new RedisClient(Options.Create(redisOptions), _logger), LazyThreadSafetyMode.ExecutionAndPublication);
            };
        }

        public IRedisClient Create(string name)
        {
            return _clients.GetOrAdd(name, _factory).Value;
        }

        public Lazy<IRedisClient> LazyCreate(string name)
        {
            return _clients.GetOrAdd(name, _factory);
        }

        public void Dispose()
        {
            lock (this)
            {
                if (_clients.Count == 0) return;
                List<Lazy<IRedisClient>> redisClients = [.. _clients.Values];
                _clients.Clear();

                foreach (var redisClient in redisClients)
                {
                    if (redisClient.IsValueCreated)
                    {
                        redisClient.Value.Dispose();
                    }
                }
                redisClients.Clear();
            }
        }
    }
}
